;(function($) {

  RuS.Spectrum = function(elm, options) {

    var _RUS_SPECTRUM = 'rus_spectrum';

    if (false === (this instanceof RuS.Spectrum)) {
      return new RuS.Spectrum(elm, options);
    }

    var defaultSettings = {
      width: 100,
      height: 100,
      axis_x_size: 20,
      axis_y_size: 40,
      device: {
        Frequency: 80000000,
        IfPanSpan: 5000,
        Bandwidth: 1000
      },
      use_canvas: 0
    };

    var normalizeDeviceSettings = function(device) {
      device.Frequency = parseInt(device.Frequency);
      device.IfPanSpan = parseInt(device.IfPanSpan);
      device.Bandwidth = parseInt(device.Bandwidth);
    };

    var settings = $.extend(true, {}, defaultSettings, options);
    normalizeDeviceSettings(settings.device);

    var _data = (function() {
      return {
        $el: elm,
        settings: settings,
        svg: createSvg(elm, settings),
        canvas: createCanvas(settings)
      };
    })();

    return {
      destroy: function() {
        elm.empty();
        return this;
      },

      update: function(data, colorArrow) {
        if (_data.settings.use_canvas) return this.updateCanvas(data, colorArrow);

        var path = '';
        if (typeof data === 'string') {
          path = data;
        }
        else {
          var max_y = 100;
          var size = data.length;
          var width = _data.settings.width - _data.settings.axis_y_size;
          var height = _data.settings.height - _data.settings.axis_x_size;

          unit_x = width / size,
              unit_y = height / max_y;

          for (var i = 0; i < size; i++) {
            if (i) {
              path += "L" + [_data.settings.axis_y_size + i * unit_x, (max_y - data[i]) * unit_y];
            }
            else {
              path += "M" + [_data.settings.axis_y_size + i * unit_x, (max_y - data[i]) * unit_y];
            }
          }
        }
        _data.svg.spectrum.attr({'path': path});

        return this;
      },

      updateCanvas: function(data, colorArrow) {
        var path = '';
        if (typeof data === 'string') {
          _data.canvas.path.setData(data);
          _data.canvas.path_layer.draw();
        }
        else {
          var context = _data.canvas.path_layer.getContext();
          _data.canvas.path_layer.clear();
          context.strokeStyle = "#00FF00";
          context.lineWidth = 1;
          context.beginPath();

          var max_y = 100;
          var size = data.length;
          var width = _data.settings.width - _data.settings.axis_y_size;
          var height = _data.settings.height - _data.settings.axis_x_size;

          unit_x = width / size,
              unit_y = height / max_y;

          for (var i = 0; i < size; i++) {
            if (i) {
              context.lineTo(i * unit_x, (max_y - data[i]) * unit_y);
            }
            else {
              context.moveTo(i * unit_x, (max_y - data[i]) * unit_y);
            }
          }

          context.stroke();
        }

        return this;
      },

      updateDeviceSettings: function(data) {
        $.extend(_data.settings.device, data);
        normalizeDeviceSettings(_data.settings.device);

        _data.svg.axis_x.remove();
        drawAxisX(_data.svg.elm, _data.settings);

        drawBandwidth(_data.svg, _data.settings);
      },

      moveFrequency: function(x) {
        var freq;
        if (x > _data.settings.axis_y_size) {
          var w = _data.settings.width - _data.settings.axis_y_size;
          var height = _data.settings.height - _data.settings.axis_x_size;
          var c = settings.axis_y_size + (settings.width - settings.axis_y_size) / 2;

          var delta = _data.settings.device.IfPanSpan * 1000 * ((x - c) / w);
          freq = ~~_data.settings.device.Frequency + delta;

          _data.svg.marker.animate({path: "M" + x + " 0L" + x + " " + height, stroke: 'yellow'}, 300, "<", function() {
            _data.svg.marker.animate({path: "Mx 0Lx h".replace(/x/g, c).replace('h', height), stroke: 'yellow'}, 300, ">");
          });
        }
        return freq;
      }
    };
  };

  var createSvg = function(elm, settings) {
    var svg;

    if (elm instanceof d3.selection) {
      elm = elm[0][0];
    }
    else if (!elm.nodeType) {
      elm = elm[0];
    }

    var width = settings.width;
    var height = settings.height;

    svg = Raphael(elm, width, height);
    //svg.canvas.setAttribute('class', 'pathview')

    svg.rect().attr({"x": settings.width - 5, "y": 0, "height": height - settings.axis_x_size, "width": 10, "stroke": "none", "fill": "#6495DC"});
    // svg.rect().attr({"x":settings.width-10,"y":0,"height":height-settings.axis_x_size,"width":10,"stroke":"none","fill":"90-#27348B:0-#1D71B8:25-#009640:50-#FFED00:75-#E30613:100"});

    return {
      elm: elm,
      bandwidth: drawBandwidth(svg, settings),
      spectrum: drawSpectrum(svg, settings),
      marker: drawMarker(svg, settings),
      axis_x: drawAxisX(elm, settings),
      axis_y: drawAxisY(elm, settings)
    };
  };

  var createCanvas = function(settings) {
    if (!settings.use_canvas) return;

    var w = settings.width - settings.axis_y_size;
    var h = settings.height - settings.axis_x_size;
    $('#canvas').css({position: 'absolute', right: 0, top: 0, width: w, height: h, overflow: 'hidden'});

    var stage = new Kinetic.Stage({
      container: 'canvas',
      width: w,
      height: h
    });

    // var layer = new Kinetic.Layer();
    // var text = new Kinetic.Text({ x: 10, y: 10, text: 'Canvas', textFill: 'darkgreen', fontSize: 20 });
    // layer.add(text);
    // stage.add(layer);

    var path = new Kinetic.Path({ x: 0, y: 0, stroke: 'green', data: '' });
    var path_layer = new Kinetic.Layer();
    path_layer.add(path);
    stage.add(path_layer);

    return {
      path_layer: path_layer,
      path: path
    };
  };

  var drawBandwidth = function(svg, settings) {
    var bandwidth = svg.bandwidth;
    var w = settings.width - settings.axis_y_size;
    if (bandwidth === undefined) {
      bandwidth = svg.rect().attr({
        "y": 0,
        "height": settings.height,
        "stroke": "none",
        "fill": "#000060"
      });
    }

    bandwidth.attr({
      "x": Math.max(settings.axis_y_size, settings.axis_y_size + (1 - settings.device.Bandwidth / settings.device.IfPanSpan) / 2 * w),
      "width": settings.device.Bandwidth / settings.device.IfPanSpan * w
    });

    return bandwidth;
  };

  var drawSpectrum = function(svg, settings) {
    return svg.path("M0,0").attr({fill: "none", stroke: "#00FF00", "stroke-width": 1});
  };

  var drawMarker = function(svg, settings) {
    var c = (settings.width + settings.axis_y_size) / 2;
    var height = settings.height - settings.axis_x_size;
    return svg
        .path("Mx 0Lx h".replace(/x/g, c).replace('h', height))
        .attr({fill: "none", stroke: "yellow", "stroke-width": 1});
  };

  var drawAxisX = function(elm, settings) {
    var s = settings;
    var scale_x = d3.scale.linear()
        .domain([settings.device.Frequency - settings.device.IfPanSpan * 1000 / 2, settings.device.Frequency + settings.device.IfPanSpan * 1000 / 2])
        .range([settings.axis_y_size, settings.width]);

    d3.select(elm).select('.axis.x').remove();

    var axis = d3.select(elm).append('g')
        .attr('class', 'axis x')
        .attr('transform', 'translate(0, TY)'.replace('TY', settings.height - settings.axis_x_size));

    axis.append('rect')
        .attr('x', settings.axis_y_size)
        .attr('width', settings.width - settings.axis_y_size)
        .attr('height', settings.axis_x_size);

    var ticks = [s.device.Frequency - s.device.IfPanSpan * 1000 / 4, s.device.Frequency, s.device.Frequency + s.device.IfPanSpan * 1000 / 4];
    axis.call(d3.svg.axis()
        .scale(scale_x)
        .orient('bottom')
        .tickSize(5)
        .tickValues(ticks));

    return axis;
  };

  var drawAxisY = function(elm, settings) {
    var s = settings;
    var scale_y = d3.scale.linear()
        .domain(settings.y_domain)
        .range([settings.height - settings.axis_x_size - 1, 0]);

    d3.select(elm).select('.axis.y').remove();

    var axis = d3.select(elm).append('g')
        .attr('class', 'axis y');

    axis.append('rect')
        .attr('width', settings.axis_y_size)
        .attr('height', settings.height);

    axis.append('text')
        .attr('x', settings.axis_y_size / 2)
        .attr('y', 15)
        .attr('text-anchor', 'middle')
        .text('dBμV');

    axis.append('g')
        .attr('transform', 'translate(TX, 0)'.replace('TX', settings.axis_y_size))
        .call(d3.svg.axis()
            .scale(scale_y)
            .orient('left')
            .tickSize(5)
            .tickValues(settings.y_ticks)
        );

    return axis;
  };

})(jQuery);
